/*
 * 描          述:  <描述>
 * 修  改   人:  PengQingyang
 * 修改时间:  2022年4月26日
 * <修改描述:>
 */
package com.tx.core.method;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;

import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.method.container.NativeInvokeContainer;
import com.tx.core.method.container.impl.DefaultNativeInvokeContainer;
import com.tx.core.method.databinder.NativeDataBinderFactory;
import com.tx.core.method.databinder.impl.DefaultNativeDataBinderFactory;
import com.tx.core.method.exceptions.MethodInvokeAccessException;
import com.tx.core.method.request.NativeInvokeRequest;
import com.tx.core.method.request.impl.MapInvokeRequest;
import com.tx.core.method.resolver.NativeMethodArgumentResolverComposite;
import com.tx.core.method.resolver.impl.MethodBodyMethodArgumentResolver;
import com.tx.core.method.resolver.impl.MethodParamBodyMethodArgumentResolver;
import com.tx.core.method.resolver.impl.MethodParamMapMethodArgumentResolver;
import com.tx.core.method.resolver.impl.MethodParamMethodArgumentResolver;

/**
 * 本地的NativeHandlerMthodInvoke工具类<br/>
 * <功能详细描述>
 * 
 * @author  PengQingyang
 * @version  [版本号, 2022年4月26日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class MethodInvokeUtils {
    
    private static NativeDataBinderFactory factory = new DefaultNativeDataBinderFactory();
    
    private static NativeMethodArgumentResolverComposite resolver = new NativeMethodArgumentResolverComposite();
    
    private static ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    
    static {
        resolver.addResolver(new MethodParamBodyMethodArgumentResolver());
        resolver.addResolver(new MethodParamMapMethodArgumentResolver());
        resolver.addResolver(new MethodParamMethodArgumentResolver());
        resolver.addResolver(new MethodBodyMethodArgumentResolver());
    }
    
    /**
     * 提交相关信息<br/>
     * <功能详细描述>
     * @param handlerMethod [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    private static void applyHandlerMethod(
            NativeInvocableHandlerMethod handlerMethod) {
        handlerMethod.setDataBinderFactory(factory);
        handlerMethod.setResolver(resolver);
        handlerMethod.setParameterNameDiscoverer(parameterNameDiscoverer);
    }
    
    /**
     * 调用指定的HandlerMethod<br/>
     * <功能详细描述>
     * @param handlerMethod
     * @param params
     * @param providedArgs
     * @return [参数说明]
     * 
     * @return Object [返回类型说明]
     * @throws Exception 
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Object invokeHandlerMethod(HandlerMethod handlerMethod,
            @Nullable NativeInvokeContainer container,
            @Nullable Map<String, Object> params,
            @Nullable Object... providedArgs) {
        AssertUtils.notNull(handlerMethod, "handlerMethod is null.");
        
        //初始化参数
        container = container == null ? new DefaultNativeInvokeContainer()
                : container;
        NativeInvocableHandlerMethod hm = null;
        if (handlerMethod instanceof NativeInvocableHandlerMethod) {
            hm = (NativeInvocableHandlerMethod) handlerMethod;
        } else {
            hm = new NativeInvocableHandlerMethod(handlerMethod);
        }
        applyHandlerMethod(hm);
        
        //调用
        NativeInvokeRequest request = new MapInvokeRequest(params);
        Object res = null;
        try {
            res = hm.invokeForRequest(request,
                    container == null ? new DefaultNativeInvokeContainer()
                            : container,
                    providedArgs);
        } catch (Exception e) {
            throw new MethodInvokeAccessException("方法调用异常.", e);
        }
        return res;
    }
    
    /**
     * 调用方法<br/>
     * <功能详细描述>
     * @param handlerMethod
     * @param params
     * @return [参数说明]
     * 
     * @return Object [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Object invokeHandlerMethod(HandlerMethod handlerMethod,
            @Nullable Map<String, Object> params) {
        AssertUtils.notNull(handlerMethod, "handlerMethod is null.");
        params = params == null ? new HashMap<>() : params;
        
        //调用
        Object res = invokeHandlerMethod(handlerMethod,
                new DefaultNativeInvokeContainer(),
                params);
        return res;
    }
    
    /**
     * 调用指定的Bean中的method方法<br/>
     * <功能详细描述>
     * @param bean
     * @param method
     * @param container
     * @param params
     * @param providedArgs
     * @return
     * @throws Exception [参数说明]
     * 
     * @return Object [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Object invokeHandlerMethod(Object bean, Method method,
            @Nullable NativeInvokeContainer container,
            @Nullable Map<String, Object> params,
            @Nullable Object... providedArgs) throws Exception {
        AssertUtils.notNull(bean, "bean is null.");
        AssertUtils.notNull(method, "method is null.");
        
        //初始化参数
        container = container == null ? new DefaultNativeInvokeContainer()
                : container;
        HandlerMethod hm = new HandlerMethod(bean, method);
        
        //调用
        Object res = invokeHandlerMethod(hm, container, params, providedArgs);
        return res;
    }
}
